/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * MainWindow.java
 *
 * Created on Aug 26, 2010, 7:25:52 PM
 */
package org.apache.directory.http.client.ui;


import java.awt.Component;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.event.TreeWillExpandListener;
import javax.swing.tree.ExpandVetoException;
import javax.swing.tree.TreePath;

import org.apache.directory.http.client.LdapHttpConnection;
import org.apache.directory.http.client.data.model.ConfigDataLoader;
import org.apache.directory.http.client.ui.callback.ConfigButtonSelectionHandler;
import org.apache.directory.http.client.ui.callback.LoginHandler;
import org.apache.directory.http.client.ui.model.EntryNode;
import org.apache.directory.http.client.ui.model.EntryTableModel;
import org.apache.directory.shared.ldap.cursor.Cursor;
import org.apache.directory.shared.ldap.entry.Entry;
import org.apache.directory.shared.ldap.filter.SearchScope;
import org.apache.directory.shared.ldap.message.BindResponse;
import org.apache.directory.shared.ldap.message.Response;
import org.apache.directory.shared.ldap.message.ResultCodeEnum;
import org.apache.directory.shared.ldap.message.SearchResultEntry;
import org.apache.directory.shared.ldap.name.DN;


/**
 *
 * @author kayyagari
 */
public class MainWindow extends javax.swing.JFrame implements LoginHandler, ConfigButtonSelectionHandler
{

    private LoginPanel loginPanel;

    private ConfigButtonPanel configBtnPanel;

    private PartitionsPanel partitonsPanel;

    private InterceptorPanel interceptorPanel;

    private LdapHttpConnection connection;

    private ConfigDataLoader dataLoader;

    private BrowserPanel browser;

    private EntryTableModel model;
    
    /** Creates new form MainWindow */
    public MainWindow()
    {
        initComponents();

        setTitle( "LDAP browser using HTTP as transport and using JSON for data exchange" );
        loginPanel = new LoginPanel();
        loginPanel.setLoginHandler( this );

        configBtnPanel = new ConfigButtonPanel();
        configBtnPanel.getBtnPartitions().setVisible( false );
        configBtnPanel.setButtonSelectionHandler( this );
        middleSplitPanel.setLeftComponent( configBtnPanel );
        configBtnPanel.setVisible( false );
        middleSplitPanel.setRightComponent( loginPanel );
        addWindowListener( new WindowAdapter()
        {

            @Override
            public void windowClosing( WindowEvent e )
            {
                try
                {
                    if( connection != null )
                    {
                        connection.unBind();
                    }
                }
                catch( Exception ex )
                {
                    ex.printStackTrace();
                }
            }
        });
    }


    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        topPanel = new javax.swing.JPanel();
        lblUserName = new javax.swing.JLabel();
        middleSplitPanel = new javax.swing.JSplitPane();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        org.jdesktop.layout.GroupLayout topPanelLayout = new org.jdesktop.layout.GroupLayout(topPanel);
        topPanel.setLayout(topPanelLayout);
        topPanelLayout.setHorizontalGroup(
            topPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(topPanelLayout.createSequentialGroup()
                .add(471, 471, 471)
                .add(lblUserName, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 159, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(334, Short.MAX_VALUE))
        );
        topPanelLayout.setVerticalGroup(
            topPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(lblUserName, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 28, Short.MAX_VALUE)
        );

        middleSplitPanel.setDividerLocation(130);

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(topPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .add(middleSplitPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 964, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .add(topPanel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(middleSplitPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 488, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents


    /**
     * @param args the command line arguments
     */
    public static void main( String args[] )
    {
        java.awt.EventQueue.invokeLater( new Runnable()
        {

            public void run()
            {
                new MainWindow().setVisible( true );
            }

        } );
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel lblUserName;
    private javax.swing.JSplitPane middleSplitPanel;
    private javax.swing.JPanel topPanel;
    // End of variables declaration//GEN-END:variables
    public void login( String userName, char[] password )
    {
        try
        {
            connection = new LdapHttpConnection( loginPanel.getServiceUrl() );
            BindResponse resp = connection.bind( userName, String.valueOf( password ) );
            if ( resp.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
            {
                loginPanel.clearPassword();
                loginPanel.setVisible( false );
                
                lblUserName.setText( userName.trim() );
                
                dataLoader = new ConfigDataLoader( connection );
                showNavigationPane();
                setRightPane( new JPanel() );
            }
            else
            {
                JOptionPane.showMessageDialog( this, resp );
            }

        }
        catch ( Exception e )
        {
            JOptionPane.showMessageDialog( this, e );
        }
    }


    public void handleConfigSelection( JButton eventSrc )
    {
        try
        {
            if ( eventSrc == configBtnPanel.getBtnPartitions() )
            {
                partitonsPanel = new PartitionsPanel();
                setRightPane( partitonsPanel );
            }
            else if ( eventSrc == configBtnPanel.getBtnInterceptors() )
            {
                interceptorPanel = new InterceptorPanel();
                interceptorPanel.setEntryData( dataLoader.getInterceptors() );
                setRightPane( interceptorPanel );
            }
            else if ( eventSrc == configBtnPanel.getBtnBrowse() )
            {
                showBrowser();
            }
        }
        catch ( Exception e )
        {
            e.printStackTrace();
        }
    }


    private void showBrowser()
    {
        try
        {
            if ( browser == null )
            {
                browser = new BrowserPanel();
                
                model = new EntryTableModel();
                
                browser.getEntryTable().setModel( model );

                EntryNode root = new EntryNode( connection.fetchRootDSE() );

                List<Entry> entries = searchEntriesUnder( DN.EMPTY_DN );

                for ( Entry e : entries )
                {
                    EntryNode node = new EntryNode( e );
                    node.setAllowsChildren( true );
                    root.add( node );
                }

                browser.setRootDse( root );

                browser.getEntryTree().addTreeWillExpandListener( new TreeWillExpandListener()
                {

                    public void treeWillExpand( TreeExpansionEvent event ) throws ExpandVetoException
                    {
                        try
                        {
                            EntryNode node = ( EntryNode ) event.getPath().getLastPathComponent();
                            browser.addEntriesToTreeUnder( searchEntriesUnder( node.getDn() ), node );
                        }
                        catch ( Exception e )
                        {
                            JOptionPane.showMessageDialog( null, e );
                        }
                    }


                    public void treeWillCollapse( TreeExpansionEvent event ) throws ExpandVetoException
                    {
                    }
                } );

                browser.getEntryTree().addTreeSelectionListener( new TreeSelectionListener()
                {

                    public void valueChanged( TreeSelectionEvent e )
                    {
                        TreePath path = e.getNewLeadSelectionPath();
                        
                        EntryNode node = ( EntryNode ) path.getLastPathComponent();
                        try
                        {
                            Entry entry = populateEntry( node.getDn() );
                            if( entry == null )
                            {
                                JOptionPane.showMessageDialog( null, "entry with DN " + node.getDn() + " doesn't exist" );
                                return;
                            }
                            
                            node.setEntry( entry );
                            model.setEntry( node.getEntry() );
                            model.fireTableDataChanged();
                        }
                        catch( Exception ex )
                        {
                            ex.printStackTrace();
                            JOptionPane.showMessageDialog( null, ex );
                        }
                    }
                } );
            }

            setRightPane( browser );
        }
        catch ( Exception e )
        {

        }
    }


    private void showNavigationPane()
    {
        middleSplitPanel.getLeftComponent().setVisible( true );
    }


    private void hideNavigationPane()
    {
        middleSplitPanel.getLeftComponent().setVisible( false );
    }


    private void setNavigationPane( Component comp )
    {
        middleSplitPanel.setLeftComponent( comp );
    }


    private void setRightPane( Component comp )
    {
        middleSplitPanel.setRightComponent( comp );
    }


    private void showRightPane()
    {
        middleSplitPanel.getRightComponent().setVisible( true );
    }


    private void hideRightPane()
    {
        middleSplitPanel.getRightComponent().setVisible( false );
    }
   
    private Entry populateEntry( DN entryDn ) throws Exception
    {
        return connection.lookup( entryDn, "*", "+" );
    }
    
    
    private List<Entry> searchEntriesUnder( DN baseDn ) throws Exception
    {
        List<Entry> entries = new ArrayList<Entry>();

        Cursor<Response> cursor = connection.search( baseDn, "(objectClass=*)", SearchScope.ONELEVEL, "1.1" );
        while ( cursor.next() )
        {
            Entry entry = ( ( SearchResultEntry ) cursor.get() ).getEntry();
            entries.add( entry );
        }

        cursor.close();
        return entries;
    }
}
